<?php
/**
 * Zend Framework Examples
 *
 * @category  Sfs
 * @package   TryIt
 * @author    Michel Corne
 * @copyright 2009 Michel Corne
 * @license   http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @see       http://zend-framework-examples.blogspot.com
 */

/*
 In this example, we get or set dates in different timezones.
 We display parts of dates and times in various formats.
 We also get informations on sunrise and sunset in several locations.
 */
/*
 Handling timezones
 */
class Sfs_Timezone
{
    private $_locale;
    private $_timezone;
    private static $_tzTerritories;

    /* Storing the timezone and the locale. */
    public function __construct($timezone = null, $locale = null)
    {
        $this->_timezone = $timezone;
        $this->_locale = $locale;
    }

    /* Identification of the timezone for the locale */
    public function findLocaleTz($inTerritory = false, $timezone = null, $locale = null)
    {
        $timezone or $timezone = $this->_timezone;
        $locale or $locale = $this->_locale;

        // We check if the timezone belongs to the locale if requested,
        // or if the timezone is valid.
        if ($inTerritory and !$this->isLocaleTz($timezone, $locale) or
        !$this->isValid($timezone)) {

            // We extract the language and the territory from the locale
            list($language, $territory) = $this->_parseLocale($locale);

            // We attempt to find the timezone from the territory,
            $territory and $timezones = self::getTzTerritories($territory) and
            $timezone = $this->_findFirstLocaleTz($timezones, $locale) or
            // or from the language name (ex. fr for France),
            $timezones = self::getTzTerritories(strtoupper($language)) and
            $timezone = $this->_findFirstLocaleTz($timezones, $locale) or
            // or from the territories corresponding to the language.
            $timezones = self::getTzTerritories($this->_getLangTerritories($language)) and
            $timezone = $this->_findFirstLocaleTz($timezones, $locale);
        }

        if (empty($timezone)) {
            // We return an error if no timezone was identified.
            throw new Exception("No timezone could be identified!");
        }

        return $timezone;
    }

    /* Verification that the timezone belongs to the locale */
    public function isLocaleTz($timezone = null, $locale = null)
    {
        $timezone or $timezone = $this->_timezone;
        $locale or $locale = $this->_locale;

        // We extract the language and the territory from the locale
        list($language, $territory) = $this->_parseLocale($locale);

        if ($territory) {
            // If there is a territory, we verify if the timezone belongs
            // to the timezones of that territory.
            $isLocaleTz = in_array($timezone, self::getTzTerritories($territory));
        } else if ($language) {
            // Or we verify that the timezone belongs to the timezones
            // of all the territories for the given language.
            $territories = $this->_getLangTerritories($language);
            $isLocaleTz = in_array($timezone, self::getTzTerritories($territories));
        } else {
            $isLocaleTz = false;
        }

        return $isLocaleTz;
    }

    /* Checking if the timezone is valid */
    public function isValid($timezone = null)
    {
        $timezone or $timezone = $this->_timezone;

        return in_array($timezone, self::getTzTerritories());
    }

    /* Extraction of the language and the territory from the locale. */
    private function _parseLocale($locale)
    {
        is_string($locale) and @list($language, $territory) = explode('_', $locale);
        empty($language) and $language = null;
        empty($territory) and $territory = null;

        return array($language, $territory);
    }

    /* Extraction of the timezones of territories */
    public static function getTzTerritories($territory = null, $sort = false)
    {
        // We get the list of timezones and territories.
        empty(self::$_tzTerritories) and
        self::$_tzTerritories = Zend_Locale::getTranslationList('territorytotimezone');

        if (is_string($territory)) {
            // We filter the timezones for a given territory.
            $timezones = array_keys(self::$_tzTerritories, $territory);
        } else if (is_array($territory)) {
            // Or we filter the timezones for a list of territories.
            $timezones = array_keys(array_intersect(self::$_tzTerritories, $territory));
        } else {
            // Or we return all the timezones.
            $timezones = array_keys(self::$_tzTerritories);
        }

        $sort and sort($timezones);

        return $timezones;
    }

    /* Finding the first timezone belonging to a locale */
    private function _findFirstLocaleTz($timezones, $locale)
    {
        $firstLocalTz = null;

        foreach($timezones as $timezone) {
            if ($this->isLocaleTz($timezone, $locale)) {
                $firstLocalTz = $timezone;
                break;
            }
        }

        return $firstLocalTz;
    }

    /* Getting the territories where a language is spoken */
    private function _getLangTerritories($language)
    {
        return explode(' ', Zend_Locale::getTranslation($language, 'territorytolanguage'));
    }

    /* Extracting a city name from a timezone */
    public static function getCity($timezone)
    {
        $pieces = explode('/', $timezone);

        return end($pieces);
    }
}